#include "GraphicsInterface.h"

//For std::sort - used when we sort the batch lists. 
#include <algorithm> 

//Include dbeug draw quad FX
#include "TexturedFullScreenQuadFX.h"

//Complete forward declarations
#include "GraphicsManager.h"
#include "D3D11Renderer.h"

//Holds data for the CSM
#include "CSM.h"

//Contains view and projection matrices to render geometry with. 
#include "VirtualCamera.h"

//Include modles
#include "StaticModel.h"
#include "StaticInstancedModel.h"
#include "AnimatedModel.h"
#include "AbstractAdvancedModel.h"

//Include others
#include "SkyDome.h"

//Include post proc/ screen space headers
#include "SSAOData.h"

//Include render states for 2D rendering - we will need to enable some states.
#include "RenderStates.h"

//Matrix that converts from NDC space [-1, 1] to tex space [0,1]
const XMMATRIX TO_TEX_SPACE_MAT(
	0.5f, 0.0f, 0.0f, 0.0f, 
	0.0f, -0.5f, 0.0f, 0.0f,
	0.0f, 0.0f, 1.0f, 0.0f, 
	0.5f, 0.5f, 0.0f, 1.0f);

//Init static data.
GraphicsInterface* GraphicsInterface::instance = 0;

//******************************************************************************
//*******************Comparison function for sorting****************************
//******************************************************************************
//
//The following functions will be used by std::Sort to sort the batches (transparent geometry)
//in to the correct order for rendering (furthest to closest)

bool StaticModelComparisonFunction(StaticModel* model0, StaticModel* model1)
{
	return true;
}

bool InstancedModelComparisonFunction(StaticInstancedModel* model0, StaticInstancedModel* model1)
{
	return true;
}

bool AnimatedModelComparisonFunction(AnimatedModel* model0, AnimatedModel* model1)
{
	return true;
}

bool AdvancedModelComparisonFunction(AbstractAdvancedModel* model0, AbstractAdvancedModel* model1)
{
	return true;
}

//******************************************************************************
//***************Constructor/Destructor/Accessor/Release/Resize*****************
//******************************************************************************

GraphicsInterface::GraphicsInterface()
	: playerCamera(0),
	  dLightArr(0),
	  dLightCount(0), 
	  skyDome(0), 
	  ssaoData(0),
	  activeEnvMap(0)
{
	//Get pointers to manager instances
	sharedGraphicsManager = GraphicsManager::GetInstance();
	//Creates the D3D11 Renderer. 
	OutputDebugStringW(L"[Creating D3D11 Renderer]\n");
	sharedD3D11Renderer = D3D11Renderer::GetInstance();

	//Allocate memory for the Directional Light Array. 
	dLightArr = new DirectionalLight[MAX_DIRECTIONAL_LIGHT_COUNT];

	//Set default hemispheric colours - these effect each models
	//ambient term. 
	hemiUpColour = XMFLOAT3(1.0f, 1.0f, 1.0f);
	hemiDownColour = XMFLOAT3(0.0f, 0.0f, 0.0f);
	hemiColRange.x = hemiUpColour.x - hemiDownColour.x;
	hemiColRange.y = hemiUpColour.y - hemiDownColour.y;
	hemiColRange.z = hemiUpColour.z - hemiDownColour.z;

	//Create debug draw quad.
	GeometryGenerator::MeshData data;
	GeometryGenerator geoGen;
	geoGen.CreateFullscreenQuad(data);

	//Create Vertex buffer
	std::vector<TexturedFullScreenQuadFX::PosTex>verts(data.Vertices.size());
	for (UINT i = 0; i < data.Vertices.size(); i++)
	{
		verts[i].Pos = data.Vertices[i].Position;
		verts[i].Tex = data.Vertices[i].TexC;
	}

	//Fill VB description
	D3D11_BUFFER_DESC bd;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.ByteWidth = sizeof(TexturedFullScreenQuadFX::PosTex) * data.Vertices.size();
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
	bd.Usage = D3D11_USAGE_IMMUTABLE;

	//Fill VB initial data desc
	D3D11_SUBRESOURCE_DATA sd;
	sd.pSysMem = &verts[0];

	//Create VB
	sharedGraphicsManager->D3DDevice()->CreateBuffer(&bd, &sd, &debugDrawQuadVB);

	//Create index buffer
	std::vector<UINT>inds(data.Indices.size());
	for (UINT i = 0; i < data.Indices.size(); i++)
		inds[i] = data.Indices[i];

	//Fill IB buffer desc.
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.ByteWidth = sizeof(UINT) * data.Indices.size();
	
	//Fill IB initial data desc.
	sd.pSysMem = &inds[0];

	//Create IB
	sharedGraphicsManager->D3DDevice()->CreateBuffer(&bd, &sd, &debugDrawQuadIB);

	//Create SSAO data
	ssaoData = new SSAOData(sharedGraphicsManager->D3DDevice(), 
		sharedGraphicsManager->ReturnBackBufferHeight(), 
		sharedGraphicsManager->ReturnBackBufferWidth(), 
		debugDrawQuadVB, debugDrawQuadIB);

	//Create the shadow map for the 0th shadow map. 
	dLightZeroShadowMapData = new DirecLightShadowMapData(GetDevice(), 
		SHADOW_MAP_RESOLUTION, SHADOW_MAP_RESOLUTION,
		NULL, NULL);

	//Create our CSM's
	csmData = new CSM();
	csmData->Init(GetDevice());

	//Shadow mapping initially enabled.
	isShadowMappingEnabled = true;
}

GraphicsInterface::~GraphicsInterface()
{
	//Destroy the D3D11Renderer
	if (sharedD3D11Renderer)
	{
		sharedD3D11Renderer->Release();
		sharedD3D11Renderer = 0;
		OutputDebugStringW(L"[Released D3D11 Renderer]\n");
	}

	//Delete directional light array
	delete []dLightArr;

	//Release quad data
	ReleaseCOM(debugDrawQuadVB);
	ReleaseCOM(debugDrawQuadIB);

	//delete SSAOData
	SafeDelete(ssaoData);

	//Delete shadow map data 
	SafeDelete(dLightZeroShadowMapData);

	//Delete Cascaded shadow maps
	SafeDelete(csmData);
}

GraphicsInterface* GraphicsInterface::GetInstance()
{
	//Create instance if not already done
	if (!instance)
		instance = new GraphicsInterface();

	//return instance pointer
	return instance;
}

void GraphicsInterface::Release()
{
	//Delete instance and set to 0
	if (instance)
	{
		delete instance;
		instance = 0;
	}
}

void GraphicsInterface::OnResize()
{
	//Resize SSAO Buffers
	if (ssaoData)
		ssaoData->Rebuild(sharedGraphicsManager->D3DDevice(), 
		sharedGraphicsManager->ReturnBackBufferHeight(), 
		sharedGraphicsManager->ReturnBackBufferWidth());
}

//******************************************************************************
//*****Functions that interact with the underlying Graphics Manager class*******
//******************************************************************************

ID3D11Device* GraphicsInterface::GetDevice()
{
	return sharedGraphicsManager->D3DDevice();
}

ID3D11DeviceContext* GraphicsInterface::GetContext()
{
	return sharedGraphicsManager->D3DImmediateContext();
}

float GraphicsInterface::ReturnBackBufferAspectRatio()
{
	//Simply return the result from the manager class. The point of this
	//is so that other classes (AbstractScene) doesnt need to include/use
	//the graphics manager - just the interface. 
	return sharedGraphicsManager->ReturnBackBufferAspectRatio();
}

float GraphicsInterface::ReturnRenderTargetHeight()
{
	return (float)sharedGraphicsManager->ReturnBackBufferHeight();
}

float GraphicsInterface::ReturnRenderTargetWidth()
{
	return (float)sharedGraphicsManager->ReturnBackBufferWidth();
}

bool GraphicsInterface::IsInFullScreenMode()
{
	//Ask the graphics managers swap chain if we are in FS mode?
	BOOL fsState;
	sharedGraphicsManager->D3DSwapChain()->GetFullscreenState(&fsState, 0);

	//Shuts up compiler warnings. Code optimization will flatten this anyway.
	if (fsState)
		return true;
	else
		return false;
}

void GraphicsInterface::Set4XMSAA(bool state)
{
	if (state)
		sharedGraphicsManager->Enable4xMSAA();
	else
		sharedGraphicsManager->Disable4xMSAA();

	//Rebuild SSAOData
	if (ssaoData)
		ssaoData->Rebuild(sharedGraphicsManager->D3DDevice(), 
		sharedGraphicsManager->ReturnBackBufferHeight(), 
		sharedGraphicsManager->ReturnBackBufferWidth());
}

//******************************************************************************
//***************Tile Based Forward Renderer Debug Functions********************
//******************************************************************************

void GraphicsInterface::DrawZPrePassFilledDepthBuffer()
{
	sharedGraphicsManager->DrawZPrePassFilledDepthBuffer();
}
	
void GraphicsInterface::DrawTileMaxZBuffer()
{
	sharedGraphicsManager->DrawTileMaxZBuffer();
}
	
void GraphicsInterface::DrawLightListStartEndBufferGreyscale()
{
	sharedGraphicsManager->DrawLightListStartEndBufferGreyscale();
}

void GraphicsInterface::DrawLightListStartEndBufferColour()
{
	sharedGraphicsManager->DrawLightListStartEndBufferColour();
}
	
void GraphicsInterface::DrawLightListStartEndBufferTransparantGreyscale()
{
	sharedGraphicsManager->DrawLightListStartEndBufferTransparantGreyscale();
}

void GraphicsInterface::DrawLightListStartEndBufferTransparantColour()
{
	sharedGraphicsManager->DrawLightListStartEndBufferTransparantColour();
}

//******************************************************************************
//**********************Other Debug Draw functions******************************
//******************************************************************************

void GraphicsInterface::DrawSSAOViewNormals()
{
	LPCSTR tech = "RGBA";
	if (sharedGraphicsManager->IsMSAAEnabled())
	{
		OutputDebugStringW(L"To Render SSAOViewNormals - Disable MSAA\n");
		tech = "RGBA_MSAA";
	}
	else
	{
		sharedD3D11Renderer->DebugDrawTexture(GetContext(), 
			debugDrawQuadVB, debugDrawQuadIB, 
			ssaoData->ReturnViewNormalDepthSRV(), 
			playerCamera->GetProjection(),
			sharedGraphicsManager->IsMSAAEnabled(),
			tech);
	}
}

void GraphicsInterface::DrawSSAOViewDepths()
{
	LPCSTR tech = "SSAOViewSpaceDepth";
	if (sharedGraphicsManager->IsMSAAEnabled())
		OutputDebugStringW(L"To Render SSAOViewDepths - Disable MSAA\n");
	else
	{
		sharedD3D11Renderer->DebugDrawTexture(GetContext(), 
			debugDrawQuadVB, debugDrawQuadIB, 
			ssaoData->ReturnViewNormalDepthSRV(),
			playerCamera->GetProjection(),
			sharedGraphicsManager->IsMSAAEnabled(),
			tech);
	}
}

void GraphicsInterface::DrawSSAOMap()
{
	LPCSTR tech = "RRR";
	if (sharedGraphicsManager->IsMSAAEnabled())
		OutputDebugStringW(L"To Render SSAOMap- Disable MSAA\n");
	else
	{
		sharedD3D11Renderer->DebugDrawTexture(GetContext(), 
			debugDrawQuadVB, debugDrawQuadIB, 
			ssaoData->ReturnSSAOMap(),
			playerCamera->GetProjection(),
			false, //Uploaded tex is not MSAA enabled, ignored. 
			tech);
	}
}

void GraphicsInterface::DrawShadowMapDepth()
{
	LPCSTR tech = "R24_UNORM_X8_TYPELESS";
	if (sharedGraphicsManager->IsMSAAEnabled())
		OutputDebugStringW(L"To Render Shadow Map- Disable MSAA\n");
	else
	{
		if (dLightCount > 0)
			sharedD3D11Renderer->DebugDrawTexture(GetContext(), 
				debugDrawQuadVB, debugDrawQuadIB, 
				dLightZeroShadowMapData->GetShadowMapSRV(),
				playerCamera->GetProjection(),
				false, //Uploaded tex is not MSAA enabled, ignored. 
				tech);
	}
}

//******************************************************************************
//***************************Update Shadow Map**********************************
//******************************************************************************

void GraphicsInterface::UpdateShadowMap(DirectionalLight* dLight)
{
	if ( (playerCamera) && (dLight) )
		dLightZeroShadowMapData->ManualUpdate(dLight, SHADOW_MAP_TRANSLATION, playerCamera);
}

//******************************************************************************
//***********Set Scene Lights for the tile based forward system.****************
//******************************************************************************

void GraphicsInterface::SetSceneLights(TileBasedLight* lightArray, unsigned count, 
	bool shouldCreateVisBuffers)
{
	sharedGraphicsManager->SetSceneLights(lightArray, count, shouldCreateVisBuffers);
}

void GraphicsInterface::UpdateSceneLights(TileBasedLight* newLightArray, 
	bool shouldCreateVisBuffers)
{
	sharedGraphicsManager->UpdateSceneLights(newLightArray, shouldCreateVisBuffers);
}

//******************************************************************************
//*******Functions that the scene programmer will (mostly) interact with********
//******************************************************************************

void GraphicsInterface::SetDirectionalLights(DirectionalLight* dLightArr, unsigned dLightCount, 
	ShadowMapBoundingSphere* sceneVolume)
{
	//Store directional light array
	if (dLightArr)
		for (unsigned i = 0; i < dLightCount; i++)
			this->dLightArr[i] = dLightArr[i];

	//And count. 
	this->dLightCount = dLightCount;

	//Ensure the dLightCount is <= to MAX_D_LIGHTS
	if (this->dLightCount > MAX_DIRECTIONAL_LIGHT_COUNT)
	{
		OutputDebugStringW(L"Graphics Interface Warning. Too many Directional Lights. Culling ");
		OutputDebugStringW(L"extra lights\n");
		//Cap to maximum.
		this->dLightCount = MAX_DIRECTIONAL_LIGHT_COUNT;
	}

	//Update the shadow map. 
	if ( (dLightZeroShadowMapData) && (this->dLightCount > 0) && (sceneVolume) )
		dLightZeroShadowMapData->Update(&dLightArr[0], sceneVolume);
}

void GraphicsInterface::SetHemisphericAmbientColours(XMFLOAT3 downColour, XMFLOAT3 upColour)
{
	//From below model
	hemiDownColour = downColour;
	//From above model
	hemiUpColour = upColour;

	//Up-Down
	hemiColRange.x = hemiUpColour.x - hemiDownColour.x;
	hemiColRange.y = hemiUpColour.y - hemiDownColour.y;
	hemiColRange.z = hemiUpColour.z - hemiDownColour.z;
}

void GraphicsInterface::SetCurrentSkyDome(SkyDome* skyDome)
{
	//Simply store a pointer to the skydome. The skydome class contains
	//the rendering code so there is no need for any fancy functionality. 
	this->skyDome = skyDome;

	//Store the SRV to the cube map.
	if (skyDome)
		activeEnvMap = skyDome->ReturnCubeMapSRV();
	else
		activeEnvMap = 0;
}

void GraphicsInterface::StartFrame(const float* backBufferClearColour, 
	VirtualCamera* playerCamera, bool shouldUpdateShadowMap)
{
	//Ensure camera is not NULL
	assert(playerCamera);

	//Clear backbuffer and bind
	sharedGraphicsManager->BindAndClearBackBufferColour(backBufferClearColour);
	//Clear depth stencil view. 
	sharedGraphicsManager->ClearDepthStencilView();

	//Store the current camera pointer
	this->playerCamera = playerCamera;

	//Clear the batches
	staticModelBatch.clear();
	staticInstModelBatch.clear();
	animModelBatch.clear();
	advModelBatch.clear();

	//Update shadow map.
	if ( (dLightCount) > 0 && (shouldUpdateShadowMap) )
		UpdateShadowMap(&dLightArr[0]);
}

void GraphicsInterface::Render(bool debugDrawLights, bool shouldDrawTransparantObjects)
{
	//**************************************************************************
	//****************************Preliminary***********************************
	//**************************************************************************
	//
	//Clear the lists of objects (vectors) that passed the frustum testlast frame
	staticModelsToRender.clear();
	staticInstModelsToRender.clear();
	animModelsToRender.clear();
	advModelsToRender.clear();

	//**************************************************************************
	//************************Build Shadow Maps*********************************
	//**************************************************************************
	//
	//If we have a single directional light (or more), bind the shadow maps DSV - disable
	//the colour writes by binding a NULL RTV
	if ( (dLightCount) > 0 && (isShadowMappingEnabled) && (dLightZeroShadowMapData) )
	{
		//Bind DSV - and then clear. 
		GetContext()->OMSetRenderTargets(0, NULL, dLightZeroShadowMapData->GetShadowMapDSV());
		GetContext()->ClearDepthStencilView(dLightZeroShadowMapData->GetShadowMapDSV(),
			D3D11_CLEAR_DEPTH, 1.0f, 0);
		GetContext()->OMSetDepthStencilState(NULL, 0);

		//Bind viewport.
		GetContext()->RSSetViewports(1, dLightZeroShadowMapData->ReturnViewport());

		//Draw (all opaque) objects in to DSV. 
		DrawStaticModels(staticModelBatch, false, true, true);
		DrawStaticInstancedModels(staticInstModelBatch, false, true, true);
		DrawAnimatedModels(animModelBatch, false, true, true);
		DrawAdvancedModels(advModelBatch, false, true, true);

#ifdef SHADOW_MAP_DRAW_TRANSPARENT_GEOMETRY
		//Draw (all transparent) objects in to DSV. 
		DrawStaticModels(staticModelBatch, false, false, true);
		DrawStaticInstancedModels(staticInstModelBatch, false, false, true);
		DrawAnimatedModels(animModelBatch, false, false, true);
		DrawAdvancedModels(advModelBatch, false, false, true);
#endif

		//Rebind prev view port
		GetContext()->RSSetViewports(1, &sharedGraphicsManager->D3DFullScreenViewport());
	}

	//**************************************************************************
	//**********************Preform frustum culling*****************************
	//**************************************************************************
	//
	//Frustum Culling for StaticModels. Outputs those that pass (ie will be drawn)
	PreformStaticModelFrustumCulling(staticModelBatch, staticModelsToRender);
	//Frustum culling for instanced models. Outputs a list of those with at least
	//one instance that will be drawn (passed the test)
	PreformStaticInstancedModelFrustumCulling(staticInstModelBatch, staticInstModelsToRender);
	//Frustum culling for animated models. Outputs those that will be drawn. Note
	//we will get some false positives here. 
	PreformAnimatedModelFrustumCulling(animModelBatch, animModelsToRender);
	//Frustum culling for the advanced models. Outputs thsoe which will be
	//drawn. 
	PreformAdvancedModelFrustumCulling(advModelBatch, advModelsToRender);
			

	//**************************************************************************
	//*******Z Pre Pass Stage (And SSAO depth/normal texture generation)********
	//**************************************************************************
	//
	//Setup the graphics manager and D3D11 for the ZPre Pass. 
	sharedGraphicsManager->BeginZPrePassStage();
	
	//Bind SSAOData::viewNormalDepthRTV as our render target view. This texture
	//stores the view space normals and depths for use when generating the
	//SSAO Map later. 
	//
	//Keep backbuffers depth buffer bound for extra efficiency. 
	float ssaoClearCol[] = {0.0f, 0.0f, -1.0f, 1e5f};
	sharedGraphicsManager->D3DImmediateContext()->ClearRenderTargetView(ssaoData->ReturnViewNormalDepthRTV(), 
		ssaoClearCol);
	ID3D11RenderTargetView* rtViews[] = {ssaoData->ReturnViewNormalDepthRTV()};
	sharedGraphicsManager->D3DImmediateContext()->OMSetRenderTargets(1, &rtViews[0], 
		sharedGraphicsManager->D3DBackBufferDepthStencilView());

	//Draw models to depth buffer - Opaque only 
	DrawStaticModels(staticModelsToRender, true, true, false);
	DrawStaticInstancedModels(staticInstModelsToRender, true, true, false);
	DrawAnimatedModels(animModelsToRender, true, true, false);
	DrawAdvancedModels(advModelsToRender, true, true, false);

	//**************************************************************************
	//****************************Generate SSAO Map*****************************
	//**************************************************************************
#ifdef ENABLE_SSAO
	ssaoData->GenerateSSAOMap(GetContext(), playerCamera);
	ssaoData->BlurSSAOMap(GetContext(), SSAO_MAP_BLUR_COUNT);
#endif

	//**************************************************************************
	//**************************Preform light culling***************************
	//**************************************************************************
	//
	//Ask the graphics manager to kick off the light culling compute shader program.
	sharedGraphicsManager->PreformLightCull(playerCamera);


	//**************************************************************************
	//************************Begin opaque drawing******************************
	//**************************************************************************
	//
	//Set up the graphics manager and D3D11 to allow colour writes - Opaque geometry.
	sharedGraphicsManager->BeginOpaqueShadingStage();

	//Draw opaque static models that passed the frustum culling test. 
	DrawStaticModels(staticModelsToRender, false, true, false);
	DrawStaticInstancedModels(staticInstModelsToRender, false, true, false);
	DrawAnimatedModels(animModelsToRender, false, true, false);
	DrawAdvancedModels(advModelsToRender, false, true, false);

	//Draw skybox if one is set.
	if (skyDome)
		skyDome->Render(GetContext(), playerCamera);

	//**************************************************************************
	//****************************Sort geometry*********************************
	//**************************************************************************
	SortGeometry(staticModelsToRender, 
		staticInstModelsToRender, 
		animModelsToRender, 
		advModelsToRender);

	//**************************************************************************
	//***********************Begin Transparant drawing**************************
	//**************************************************************************
	//
	//Set up the graphics manager and D3D11 for transparant geometry drawing. 
	sharedGraphicsManager->BeginTransparantShadingStage();

	//Draw Transparant static models. 
	if (shouldDrawTransparantObjects)
	{
		DrawStaticModels(staticModelsToRender, false, false, false);
		DrawStaticInstancedModels(staticInstModelsToRender, false, false, false);
		DrawAnimatedModels(animModelsToRender, false, false, false);
		DrawAdvancedModels(advModelsToRender, false, false, false);
	}

	//**************************************************************************
	//****************************Post-Processing*******************************
	//**************************************************************************


	//**************************************************************************
	//*****************************Debug Drawing********************************
	//**************************************************************************
	//
	//Disable alpha blending before debug drawing things (Eg, the lights
	sharedGraphicsManager->D3DImmediateContext()->OMSetBlendState(NULL, NULL, 0xffffffff); 
	
	//Draw lights
	if (debugDrawLights)
		sharedGraphicsManager->DrawLights(playerCamera);
}

void GraphicsInterface::EndFrame(bool vysnc)
{
	//Page flip only for the time being.
	sharedGraphicsManager->Present(vysnc);
}

//******************************************************************************
//****************************2D Rendering**************************************
//******************************************************************************

void GraphicsInterface::Begin2DRendering()
{
	//Enable alpha blending. 
	float blendFactor[4] = {1.0f};
	GetContext()->OMSetBlendState(RenderStates::trans2DBS, blendFactor, 0xffffffff);
}
	
void GraphicsInterface::End2DRendering()
{
	//restore default blend state
	float blendFactor[4] = {1.0f};
	GetContext()->OMSetBlendState(NULL, blendFactor, 0xffffffff);
}

//******************************************************************************
//*****************************Model Bacth**************************************
//******************************************************************************

void GraphicsInterface::AddModelToBatch(StaticModel* model)
{
	//Add object to the batch. 
	if (model->isInit)
		staticModelBatch.push_back(model);
	else
		OutputDebugStringW(L"Graphics Interface Warning: Model can not be added to batch - isInit == false\n");
}

void GraphicsInterface::AddModelToBatch(StaticInstancedModel* model)
{
	//Add inst model to inst batch
	if (model->staticModel->isInit)
	{
		staticInstModelBatch.push_back(model);
		
		//After adding to batch, go through and ensure that all models
		//are added to the instance buffer that should be rendered. 
		if (dLightCount > 0)
		{
			//Reset to 0. 
			model->numInstancesPassedFrustumTest = 0;

			//Map to the instance data VB - Discarding old data.
			D3D11_MAPPED_SUBRESOURCE mappedData;
			HR(sharedGraphicsManager->D3DImmediateContext()->Map(
				model->instancedBuffer, 0, D3D11_MAP_WRITE_DISCARD, 
				0, &mappedData));

			//Reinterpret(cast) the mappedData to an XMFLOAT4X4 poiter
			XMFLOAT4X4* d = reinterpret_cast<XMFLOAT4X4*>(mappedData.pData);

			//Update contents of the vertex buffer
			for (unsigned i = 0; i < model->ReturnInstanceCount(); i++)
			{
				//Copy every active model. 
				if (model->GetInstanceData(i)->Active)
				{
					//Construct world matrix
					XMMATRIX trans = XMMatrixTranslation(model->GetInstanceData(i)->Pos.x,
						model->GetInstanceData(i)->Pos.y, model->GetInstanceData(i)->Pos.z);

					XMMATRIX scale = XMMatrixScaling(model->GetInstanceData(i)->Scale.x, 
						model->GetInstanceData(i)->Scale.y, model->GetInstanceData(i)->Scale.z);
				
					XMMATRIX rotX = XMMatrixRotationX(model->GetInstanceData(i)->Rot.x);
					XMMATRIX rotY = XMMatrixRotationY(model->GetInstanceData(i)->Rot.y);
					XMMATRIX rotZ = XMMatrixRotationZ(model->GetInstanceData(i)->Rot.z);

					XMMATRIX rot = rotX * rotY * rotZ;
					XMMATRIX wd = (scale * rot) * trans;

					//Store world.
					XMStoreFloat4x4(&d[model->numInstancesPassedFrustumTest], 
						wd);
		
					//Increment
					model->numInstancesPassedFrustumTest++;
				}
			}

			//Once done, unmap.
			sharedGraphicsManager->D3DImmediateContext()->Unmap(model->instancedBuffer, 0);
		}
	}
	else
		OutputDebugStringW(L"Graphics Interface Warning: Inst model can not be added to bathc - isInit == false\n");
}

void GraphicsInterface::AddModelToBatch(AnimatedModel* model)
{
	//Add Anim model to inst batch
	if (model->isInit)
		animModelBatch.push_back(model);
	else
		OutputDebugStringW(L"Graphics Interface Warning: Amim model can not be added to batch - isInit == false\n");
}

void GraphicsInterface::AddModelToBatch(AbstractAdvancedModel* model)
{
	if (model->isInit)
	{
		advModelBatch.push_back(model);
		//Also pass the message to the advanced model that it has been
		//added to the batch
		model->OnBatchAdd(this);
	}
	else
	{
		OutputDebugStringW(L"Graphics Interface Warning: Adv Model can not be added to batch - isInit == false\n");
		OutputDebugStringW(L"Note: This could be because your advanced model subclass does not set the flag...\n");
	}
}
//******************************************************************************
//***************************Internal functions*********************************
//******************************************************************************

//******************************************************************************
//***************************Geometry Sorting***********************************
//******************************************************************************
void GraphicsInterface::SortGeometry(std::vector<StaticModel*>&staticModels, 
		std::vector<StaticInstancedModel*>&staticInstModels, 
		std::vector<AnimatedModel*>&animModels, 
		std::vector<AbstractAdvancedModel*>&adModels)
{

}

//******************************************************************************
//***************************Frustum Culling************************************
//******************************************************************************

void GraphicsInterface::PreformStaticModelFrustumCulling(
	std::vector<StaticModel*> &staticModelsInput,
	std::vector<StaticModel*> &staticModelsPass)
{
	//Loop through every static model in the batch and preform the frustum-AABB test.
	std::vector<StaticModel*>::iterator it;
	it = staticModelsInput.begin();
	while(it != staticModelsInput.end())
	{
		//Transform camera frustum to local space of this model. 
		XNA::Frustum frustumL;
		playerCamera->ReturnFrustumInLocalSpace(&(*it)->worldMatrix, &frustumL);

		//Preform frustum - AABB intersection test in local space of the object. If it
		//passes, add to the successful batch list. 
		if (XNA::IntersectAxisAlignedBoxFrustum(&(*it)->aabbL, &frustumL))
			staticModelsPass.push_back((*it));
	
		//Next model
		it++;
	}
}

void GraphicsInterface::PreformStaticInstancedModelFrustumCulling(
	std::vector<StaticInstancedModel*> &staticInstancedModelInput,
	std::vector<StaticInstancedModel*> &staticInstancedModelpass)
{
	//Iterator used to loop through instances of each instanced model
	std::vector<InstanceData>::iterator iit;

	//Loop through every static instanced model in the input batch
	std::vector<StaticInstancedModel*>::iterator it;
	it = staticInstancedModelInput.begin();
	while(it != staticInstancedModelInput.end())
	{
		//Reset the instances to draw count for this instanced model
		(*it)->numInstancesPassedFrustumTest = 0;

		//Vector XMFLOAt4X4 matricies (world matrix) - we will push
		//a new matrix every time an instance passes the frustum test.
		std::vector<XMFLOAT4X4>instData;

		//Loop through every instance of the model
		iit = (*it)->instances.begin();
		while (iit != (*it)->instances.end())
		{
			//Only preform the checks if this instance is active
			if (iit->Active)
			{
				//Construct world matrix
				XMMATRIX trans = XMMatrixTranslation(iit->Pos.x, iit->Pos.y, iit->Pos.z);
				XMMATRIX scale = XMMatrixScaling(iit->Scale.x, iit->Scale.y, iit->Scale.z);
				XMMATRIX rotX = XMMatrixRotationX(iit->Rot.x);
				XMMATRIX rotY = XMMatrixRotationY(iit->Rot.y);
				XMMATRIX rotZ = XMMatrixRotationZ(iit->Rot.z);
				XMMATRIX rot = rotX * rotY * rotZ;

				XMMATRIX wd = (scale * rot) * trans;
				XMFLOAT4X4 world;
				XMStoreFloat4x4(&world, wd);

				//Preform frustum test:
				//
				//Transform camera frustum to the local space of the instance in question
				XNA::Frustum frustumL;
				playerCamera->ReturnFrustumInLocalSpace(&world, &frustumL);

				//Preform frustum - AABB intersection test in local space of the object.
				//If it passes, add the world matrix to the vector for this static instanced
				//model. Also, increment the numInstancesToDraw count
				if (XNA::IntersectAxisAlignedBoxFrustum(&(*it)->staticModel->aabbL, &frustumL))
				{
					instData.push_back(world);
					(*it)->numInstancesPassedFrustumTest++;
				}//if (XNA::IntersecAABF())
			}//End if (iit->Active)

			//Next instance
			iit++;
		}//End while(iit)

		//Before moving on, we need to update the instance buffer with the 
		//data from instData vector above.
		//
		//Use the mapping API. Buffer will have been created with CPU
		//access flag and as a Dynamic Buffer. 
		if ((*it)->numInstancesPassedFrustumTest)
		{
			//Map to the instance data VB - Discarding old data.
			D3D11_MAPPED_SUBRESOURCE mappedData;
			HR(sharedGraphicsManager->D3DImmediateContext()->Map(
				(*it)->instancedBuffer, 0, D3D11_MAP_WRITE_DISCARD, 
				0, &mappedData));

			//Reinterpret(cast) the mappedData to an XMFLOAT4X4 poiter
			XMFLOAT4X4* d = reinterpret_cast<XMFLOAT4X4*>(mappedData.pData);

			//Update contents of the vertex buffer
			for (unsigned i = 0; i < (*it)->numInstancesPassedFrustumTest; i++)
				d[i] = instData[i];

			//Once done, unmap.
			sharedGraphicsManager->D3DImmediateContext()->Unmap((*it)->instancedBuffer, 0);

			//Also add this model to the output batch
			staticInstancedModelpass.push_back((*it));
		}//End if ((*it)->numInstancesPassedFrustumTest)

		//Next model
		it++;
	}//End while(it)
}

void GraphicsInterface::PreformAnimatedModelFrustumCulling(
		std::vector<AnimatedModel*> &animModelsInput,
		std::vector<AnimatedModel*> &animModelsPass)
{
	//Loop through every anim model in the batch and preform the frustum-AABB test.
	std::vector<AnimatedModel*>::iterator it;
	it = animModelsInput.begin();
	while(it != animModelsInput.end())
	{
		//Transform camera frustum to local space of this model. 
		XNA::Frustum frustumL;
		playerCamera->ReturnFrustumInLocalSpace(&(*it)->worldMatrix, &frustumL);

		//Preform frustum - AABB intersection test in local space of the object. If it
		//passes, add to the successful batch list. 
		if (XNA::IntersectAxisAlignedBoxFrustum(&(*it)->aabbL, &frustumL))
			animModelsPass.push_back((*it));
	
		//Next model
		it++;
	}
}

void GraphicsInterface::PreformAdvancedModelFrustumCulling(
		std::vector<AbstractAdvancedModel*> &advModelsInput, 
		std::vector<AbstractAdvancedModel*> &advModelsPass)
{
	//Loop through every anim model in the batch and preform the frustum-AABB test.
	std::vector<AbstractAdvancedModel*>::iterator it;
	it = advModelsInput.begin();
	while(it != advModelsInput.end())
	{
		//If the subclass handles the frustum culling itself, 
		//then add to the to render batch. 
		if((*it)->subclassManagesFrustumCulling)
			advModelsPass.push_back((*it));
		else
		{
			//Transform camera frustum to local space of this model. 
			XNA::Frustum frustumL;
			playerCamera->ReturnFrustumInLocalSpace(&(*it)->worldMatrix, &frustumL);

			//Preform frustum - AABB intersection test in local space of the object. If it
			//passes, add to the successful batch list. 
			if (XNA::IntersectAxisAlignedBoxFrustum(&(*it)->aabbL, &frustumL))
				advModelsPass.push_back((*it));
		}

		//Next model
		it++;
	}
}

//******************************************************************************
//***************************Draw Functions*************************************
//******************************************************************************

//******************************************************************************
//************************Draw Entry Functions**********************************
//******************************************************************************

void GraphicsInterface::DrawStaticModels(std::vector<StaticModel*> &modelsToRender, 
	bool zPrePass, bool isOpaquePass, bool isShadowPass)
{
	//Loop through the static models that are to be rendered. 
	std::vector<StaticModel*>::iterator it;
	it = modelsToRender.begin();

	//Which view and projection matrix to use - either the player cameras
	//or the shadow maps.
	XMMATRIX view;
	XMMATRIX proj;

	if (isShadowPass)
	{
		view = dLightZeroShadowMapData->GetLightView();
		proj = dLightZeroShadowMapData->GetLightProj();
	}
	else
	{
		view = playerCamera->GetView();
		proj = playerCamera->GetProjection();
	}

	while(it != modelsToRender.end())
	{
		//Loop through materials for this model.
		for (unsigned i = 0; i < (*it)->subModels.size(); i++)
		{
			//Does this submodel (which is a small portion of an entire model) 
			//opacity flag match that of the passed in isOpaquePass? If yes, render. Else
			//ignore for now (either been rendered already or will be soon)
			if ((*it)->subModels[i]->IsOpaque == isOpaquePass)
			{
				//If shadow pass, see if this model should cast shadows.
				if ( (isShadowPass) && ((*it)->isShadowCaster == false) )
					continue;

				//Decide which effect to render with. 
				if ( ((*it)->subModels[i]->IsUsingDisplacementMapping) )
					DrawStaticModelDisplacementMapping((*it), i, zPrePass, isShadowPass, view, proj);
				else if ( ((*it)->subModels[i]->NormalMap) )
					DrawStaticModelNormalMapping((*it), i, zPrePass, isShadowPass, view, proj);
				else if ( ((*it)->subModels[i]->TextureMap) )
					DrawStaticModelTextureMapping((*it), i, zPrePass, isShadowPass, view, proj);
				else
					DrawStaticModelPlainColour((*it), i, zPrePass, isShadowPass, view, proj);
			}
		}

		//Next model.
		it++;
	}
}

void GraphicsInterface::DrawStaticInstancedModels(
	std::vector<StaticInstancedModel*> &modelsToRender,
	bool zPrePass, bool isOpaquePass, bool isShadowPass)
{
	//Loop through the static instanced models that have been input.
	std::vector<StaticInstancedModel*>::iterator it;
	it = modelsToRender.begin();

	//Which view and projection matrix to use - either the player cameras
	//or the shadow maps.
	XMMATRIX view;
	XMMATRIX proj;

	if (isShadowPass)
	{
		view = dLightZeroShadowMapData->GetLightView();
		proj = dLightZeroShadowMapData->GetLightProj();
	}
	else
	{
		view = playerCamera->GetView();
		proj = playerCamera->GetProjection();
	}

	while(it != modelsToRender.end())
	{
		//Loop through submodels
		for (unsigned i = 0; i < (*it)->staticModel->subModels.size(); i++)
		{
			//Render model if the opacity flag of the sub model matches
			//the flag passed in. 
			if ((*it)->staticModel->subModels[i]->IsOpaque == isOpaquePass)
			{
				//Decide which effect to render with.
				if ((*it)->staticModel->subModels[i]->IsUsingDisplacementMapping)
					DrawStaticInstancedModelDisplacementMapping(*it, i, zPrePass, isShadowPass, view, proj);
				else if ((*it)->staticModel->subModels[i]->NormalMap)
					DrawStaticInstancedModelNormalMapping(*it, i, zPrePass, isShadowPass, view, proj);
				else if ((*it)->staticModel->subModels[i]->TextureMap)
					DrawStaticInstancedModelTextureMapping(*it, i, zPrePass, isShadowPass, view, proj);
				else
					DrawStaticInstancedModelSolidColour(*it, i, zPrePass, isShadowPass, view, proj);
			}
		}//End for (i)

		//Next instanced model
		it++;
	}
}

void GraphicsInterface::DrawAnimatedModels(std::vector<AnimatedModel*> &modelsToRender,
		bool zPrePass, bool isOpaquePass, bool isShadowPass)
{
	//Loop through the static models that are to be rendered. 
	std::vector<AnimatedModel*>::iterator it;
	it = modelsToRender.begin();

	//Which view and projection matrix to use - either the player cameras
	//or the shadow maps.
	XMMATRIX view;
	XMMATRIX proj;

	if (isShadowPass)
	{
		view = dLightZeroShadowMapData->GetLightView();
		proj = dLightZeroShadowMapData->GetLightProj();
	}
	else
	{
		view = playerCamera->GetView();
		proj = playerCamera->GetProjection();
	}

	while(it != modelsToRender.end())
	{
		//Loop through materials for this model.
		for (unsigned i = 0; i < (*it)->subModels.size(); i++)
		{
			//Does this submodel (which is a small portion of an entire model) 
			//opacity flag match that of the passed in isOpaquePass? If yes, render. Else
			//ignore for now (either been rendered already or will be soon)
			if ((*it)->subModels[i]->IsOpaque == isOpaquePass)
			{
				//If shadow pass, see if this model should cast shadows.
				if ( (isShadowPass) && ((*it)->isShadowCaster == false) )
					continue;

				//Decide which effect to render with. 
				if ( ((*it)->subModels[i]->NormalMap) )
					DrawAnimatedModelNormalMapping((*it), i, zPrePass, isShadowPass, view, proj);
				else if ( ((*it)->subModels[i]->TextureMap) )
					DrawAnimatedModelTextureMapping((*it), i, zPrePass, isShadowPass, view, proj);
				else
					DrawAnimatedModelSolidColour((*it), i, zPrePass, isShadowPass, view, proj);
			}
		}

		//Next model.
		it++;
	}
}

void GraphicsInterface::DrawAdvancedModels(std::vector<AbstractAdvancedModel*> &modelsToRender, 
		bool zPrePass, bool isOpaquePass, bool isShadowPass)
{
	//Unlike the above functions, we do not use the renderer to render
	//advanced models. Instead, we pass the responsability to render
	//back to the advanced model though its overriden 
	//Render() function. 

	//Do we have a shadow map?
	DirecLightShadowMapData* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData;

	//Which view and projection matrix to use - either the player cameras
	//or the shadow maps.
	XMMATRIX view;
	XMMATRIX proj;

	if (isShadowPass)
	{
		view = dLightZeroShadowMapData->GetLightView();
		proj = dLightZeroShadowMapData->GetLightProj();
	}
	else
	{
		view = playerCamera->GetView();
		proj = playerCamera->GetProjection();
	}

	//Loop through all models we should render. 
	std::vector<AbstractAdvancedModel*>::iterator it;
	it = modelsToRender.begin();
	while(it != modelsToRender.end())
	{
		//Ask the model to render. 
		(*it)->Render(zPrePass, isOpaquePass, isShadowPass, 
			playerCamera, 
			shadowMap, 
			ssaoData, 
			activeEnvMap, 
			sharedGraphicsManager->ReturnLightListBufferSRV(),
			//Opaque
			sharedGraphicsManager->ReturnLightListIndexBufferSRV(), 
			sharedGraphicsManager->ReturnLightListStartEndBufferSRV(), 
			//Transparant
			sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV(),  
			sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV(),
			dLightArr, dLightCount, 
			hemiDownColour, hemiColRange,
			view, proj,
			GetContext());

		//Next model
		it++;
	}
}

//******************************************************************************
//*********************Static Model Draw Functions******************************
//******************************************************************************

void GraphicsInterface::DrawStaticModelTextureMapping(StaticModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * view) * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->subModels[mIndex]->TexTrans);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardTextureMapFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(),
		dLightArr, dLightCount,
		llib, 
		llseb,
		mod->subModels[mIndex]->vb,
		mod->subModels[mIndex]->ib,
		wd, wit, wvp, tex, 
		mod->subModels[mIndex]->Mat, 
		mod->subModels[mIndex]->TextureMap, 
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex,
		zPrePass, 
		mod->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		wv, 
		ssaoData->ReturnSSAOMap(), 
		ssaoTrans, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex(), 
		mod->shouldSampleSSAOMap);
}

void GraphicsInterface::DrawStaticModelNormalMapping(StaticModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * view) * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->subModels[mIndex]->TexTrans);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardNormalMapFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, 
		llseb,
		mod->subModels[mIndex]->vb,
		mod->subModels[mIndex]->ib,
		wd, wit, wvp, tex, 
		mod->subModels[mIndex]->Mat,
		mod->subModels[mIndex]->TextureMap, 
		mod->subModels[mIndex]->NormalMap,
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex,
		zPrePass, 
		mod->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		wv, 
		ssaoData->ReturnSSAOMap(), 
		ssaoTrans, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex(), 
		mod->shouldSampleSSAOMap);
}

void GraphicsInterface::DrawStaticModelDisplacementMapping(StaticModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, viewProj, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX vp = view * proj;
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * vp);
	XMMATRIX tex = XMLoadFloat4x4(&mod->subModels[mIndex]->TexTrans);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardDisplacementMapFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb,
		mod->subModels[mIndex]->vb,
		mod->subModels[mIndex]->ib,
		wd, vp, wit, wvp, tex, 
		mod->subModels[mIndex]->Mat,
		mod->subModels[mIndex]->TextureMap,
		mod->subModels[mIndex]->NormalMap, 
		mod->subModels[mIndex]->HeightMap,
		mod->subModels[mIndex]->TessData.HeightScale,
		mod->subModels[mIndex]->TessData.MaxTessDistance,
		mod->subModels[mIndex]->TessData.MinTessDistance,
		mod->subModels[mIndex]->TessData.MaxTessFactor,
		mod->subModels[mIndex]->TessData.MinTessFactor,
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex, 
		zPrePass, 
		mod->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		wv, view, 
		ssaoData->ReturnSSAOMap(), 
		TO_TEX_SPACE_MAT, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex(), 
		mod->shouldSampleSSAOMap);
}

void GraphicsInterface::DrawStaticModelPlainColour(StaticModel* mod,
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX vp = view * proj;
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * vp);
	XMMATRIX tex = XMLoadFloat4x4(&mod->subModels[mIndex]->TexTrans);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Take diffuse colour as our colour to send.
	XMFLOAT3 col;
	col.x = mod->subModels[mIndex]->Mat.Diffuse.x;
	col.y = mod->subModels[mIndex]->Mat.Diffuse.y;
	col.z = mod->subModels[mIndex]->Mat.Diffuse.z;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw with correct effect.
	sharedD3D11Renderer->RenderWithTileForwardSolidColourFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb,
		mod->subModels[mIndex]->vb, 
		mod->subModels[mIndex]->ib, 
		wd, wit, wvp, 
		mod->subModels[mIndex]->Mat, 
		col,
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex, 
		zPrePass, 
		mod->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		wv, 
		ssaoData->ReturnSSAOMap(), 
		ssaoTrans, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex(), 
		mod->shouldSampleSSAOMap);
}

//******************************************************************************
//***************Static Instanced Model Draw Functions**************************
//******************************************************************************

void GraphicsInterface::DrawStaticInstancedModelNormalMapping(StaticInstancedModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout viewProjection matrix and tex transform.
	XMMATRIX vp = view * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->staticModel->subModels[mIndex]->TexTrans);

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->staticModel->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardNormalMapInstFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb, 
		mod->staticModel->subModels[mIndex]->vb,
		mod->staticModel->subModels[mIndex]->ib,
		mod->instancedBuffer, 
		vp, tex,
		mod->staticModel->subModels[mIndex]->Mat,
		mod->staticModel->subModels[mIndex]->TextureMap,
		mod->staticModel->subModels[mIndex]->NormalMap,
		mod->staticModel->subModels[mIndex]->DrawCount,
		mod->staticModel->subModels[mIndex]->StartDrawIndex,
		mod->numInstancesPassedFrustumTest, 
		zPrePass, 
		mod->staticModel->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		view, 
		ssaoData->ReturnSSAOMap(), 
		TO_TEX_SPACE_MAT, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}

void GraphicsInterface::DrawStaticInstancedModelTextureMapping(StaticInstancedModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout viewProjection matrix and tex transform.
	XMMATRIX vp = view * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->staticModel->subModels[mIndex]->TexTrans);

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->staticModel->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardTextureMapInstFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb, 
		mod->staticModel->subModels[mIndex]->vb,
		mod->staticModel->subModels[mIndex]->ib,
		mod->instancedBuffer, 
		vp, tex,
		mod->staticModel->subModels[mIndex]->Mat,
		mod->staticModel->subModels[mIndex]->TextureMap,
		mod->staticModel->subModels[mIndex]->DrawCount,
		mod->staticModel->subModels[mIndex]->StartDrawIndex,
		mod->numInstancesPassedFrustumTest, 
		zPrePass, 
		mod->staticModel->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		view, 
		ssaoData->ReturnSSAOMap(), 
		TO_TEX_SPACE_MAT, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}

void GraphicsInterface::DrawStaticInstancedModelSolidColour(StaticInstancedModel* mod,
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout viewProjection matrix.
	XMMATRIX vp = view * proj;

	//Take diffuse colour as our colour to send.
	XMFLOAT3 col;
	col.x = mod->staticModel->subModels[mIndex]->Mat.Diffuse.x;
	col.y = mod->staticModel->subModels[mIndex]->Mat.Diffuse.y;
	col.z = mod->staticModel->subModels[mIndex]->Mat.Diffuse.z;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->staticModel->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardSolidColourInstFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb, 
		mod->staticModel->subModels[mIndex]->vb,
		mod->staticModel->subModels[mIndex]->ib,
		mod->instancedBuffer, 
		vp,
		mod->staticModel->subModels[mIndex]->Mat,
		col,
		mod->staticModel->subModels[mIndex]->DrawCount,
		mod->staticModel->subModels[mIndex]->StartDrawIndex,
		mod->numInstancesPassedFrustumTest, 
		zPrePass, 
		mod->staticModel->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange, 
		view, 
		ssaoData->ReturnSSAOMap(), 
		TO_TEX_SPACE_MAT, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}

void GraphicsInterface::DrawStaticInstancedModelDisplacementMapping(StaticInstancedModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout viewProjection matrix and tex transform.
	XMMATRIX vp = view * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->staticModel->subModels[mIndex]->TexTrans);

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->staticModel->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardDisplacementMapInstFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb, 
		mod->staticModel->subModels[mIndex]->vb,
		mod->staticModel->subModels[mIndex]->ib,
		mod->instancedBuffer, 
		vp, tex,
		mod->staticModel->subModels[mIndex]->Mat,
		mod->staticModel->subModels[mIndex]->TextureMap,
		mod->staticModel->subModels[mIndex]->NormalMap,
		mod->staticModel->subModels[mIndex]->HeightMap,
		mod->staticModel->subModels[mIndex]->TessData.HeightScale,
		mod->staticModel->subModels[mIndex]->TessData.MaxTessDistance,
		mod->staticModel->subModels[mIndex]->TessData.MinTessDistance,
		mod->staticModel->subModels[mIndex]->TessData.MaxTessFactor,
		mod->staticModel->subModels[mIndex]->TessData.MinTessFactor,
		mod->staticModel->subModels[mIndex]->DrawCount,
		mod->staticModel->subModels[mIndex]->StartDrawIndex,
		mod->numInstancesPassedFrustumTest, 
		zPrePass, 
		mod->staticModel->subModels[mIndex]->Topology,
		hemiDownColour, hemiColRange,
		view, 
		ssaoData->ReturnSSAOMap(), 
		TO_TEX_SPACE_MAT, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}

//******************************************************************************
//******************Animated Model Draw Functions*******************************
//******************************************************************************

void GraphicsInterface::DrawAnimatedModelNormalMapping(AnimatedModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * view) * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->subModels[mIndex]->TexTrans);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardAnimNormalMapFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, 
		llseb,
		mod->subModels[mIndex]->vb,
		mod->subModels[mIndex]->ib,
		wd, wit, wvp, tex, 
		mod->subModels[mIndex]->Mat, 
		mod->subModels[mIndex]->TextureMap, 
		mod->subModels[mIndex]->NormalMap,
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex,
		zPrePass, 
		mod->subModels[mIndex]->Topology, 
		mod->GetFinalTransforms(), 
		mod->GetNumFinalTransforms(),
		hemiDownColour, hemiColRange, 
		wv, 
		ssaoData->ReturnSSAOMap(), 
		ssaoTrans, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}

void GraphicsInterface::DrawAnimatedModelTextureMapping(AnimatedModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * view) * proj;
	XMMATRIX tex = XMLoadFloat4x4(&mod->subModels[mIndex]->TexTrans);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw this model with texture mapping only.
	sharedD3D11Renderer->RenderWithTileForwardAnimTextureMapFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(),
		dLightArr, dLightCount,
		llib, 
		llseb,
		mod->subModels[mIndex]->vb,
		mod->subModels[mIndex]->ib,
		wd, wit, wvp, tex, 
		mod->subModels[mIndex]->Mat, 
		mod->subModels[mIndex]->TextureMap, 
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex,
		zPrePass, 
		mod->subModels[mIndex]->Topology, 
		mod->GetFinalTransforms(), 
		mod->GetNumFinalTransforms(),
		hemiDownColour, hemiColRange, 
		wv, 
		ssaoData->ReturnSSAOMap(), 
		ssaoTrans, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}

void GraphicsInterface::DrawAnimatedModelSolidColour(AnimatedModel* mod, 
	unsigned mIndex, bool zPrePass,
	bool isShadowPass, CXMMATRIX &view, CXMMATRIX &proj)
{
	//Workout world matrix, worldViewProj, worldInverse and load in to XMMATRIX.
	XMMATRIX wd = XMLoadFloat4x4(&mod->worldMatrix);
	XMMATRIX vp = view * proj;
	XMMATRIX wit = MathHelper::InverseTranspose(wd);
	XMMATRIX wvp = (wd * vp);
	XMMATRIX wv = wd * view;
	XMMATRIX ssaoTrans = wvp * TO_TEX_SPACE_MAT;

	//Take diffuse colour as our colour to send.
	XMFLOAT3 col;
	col.x = mod->subModels[mIndex]->Mat.Diffuse.x;
	col.y = mod->subModels[mIndex]->Mat.Diffuse.y;
	col.z = mod->subModels[mIndex]->Mat.Diffuse.z;

	//Get correct LLIB and LLSEB
	ID3D11ShaderResourceView* llib;
	ID3D11ShaderResourceView* llseb;

	if (mod->subModels[mIndex]->IsOpaque)
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferSRV();
		llseb = sharedGraphicsManager->ReturnLightListStartEndBufferSRV();
	}
	else
	{
		llib = sharedGraphicsManager->ReturnLightListIndexBufferTransparantSRV();
		llseb = sharedGraphicsManager->ReturnlightListStartEndBufferTransparantSRV();
	}

	//Do we have a shadow map?
	ID3D11ShaderResourceView* shadowMap = 0;
	if (dLightCount > 0 && isShadowMappingEnabled)
		shadowMap = dLightZeroShadowMapData->GetShadowMapSRV();

	//Ask renderer to draw with correct effect.
	sharedD3D11Renderer->RenderWithTileForwardAnimSolidColourFX(
		sharedGraphicsManager->D3DImmediateContext(), 
		playerCamera->GetPosition(), 
		dLightArr, dLightCount, 
		llib, llseb,
		mod->subModels[mIndex]->vb, 
		mod->subModels[mIndex]->ib, 
		wd, wit, wvp, 
		mod->subModels[mIndex]->Mat, 
		col,
		mod->subModels[mIndex]->DrawCount, 
		mod->subModels[mIndex]->StartDrawIndex, 
		zPrePass, 
		mod->subModels[mIndex]->Topology, 
		mod->GetFinalTransforms(), 
		mod->GetNumFinalTransforms(),
		hemiDownColour, hemiColRange, 
		wv, 
		ssaoData->ReturnSSAOMap(), 
		ssaoTrans, 
		activeEnvMap, 
		isShadowPass, 
		shadowMap,
		dLightZeroShadowMapData->GetLightView(), 
		dLightZeroShadowMapData->GetLightProj(), 
		dLightZeroShadowMapData->GetNDCToTex());
}